#pragma once

#include "rating.hh"

#include <string>
#include <memory>
#include <tuple>

enum class RuleType
{
    Accept,
    Reject,
    Judgment,
    Jump,
};

enum class RuleResult
{
    Accept,
    Reject,
    Next,
    Jump,
};

class Rule
{
public:
    Rule(RuleType type) : 
        _type{type} {}
    
public:
    virtual auto result(Rating* rating) -> std::tuple<RuleResult, std::string> const = 0;
    virtual void print() const = 0;

protected:
    RuleType _type;
};

class AcceptRule : public Rule
{
public:
    AcceptRule() : Rule{RuleType::Accept} {}

public:
    virtual auto result(Rating* rating) -> std::tuple<RuleResult, std::string> const override;
    virtual void print() const override;
};

class RejectRule : public Rule
{
public:
    RejectRule() : Rule{RuleType::Reject} {}

public:
    virtual auto result(Rating* rating) -> std::tuple<RuleResult, std::string> const override;
    virtual void print() const override;
};

enum class RuleOpertion
{
    Greater,
    Less,
};

class JudgmentRule : public Rule
{
public:
    JudgmentRule(char attr, RuleOpertion oper, int value, std::string workflow) : 
        Rule{RuleType::Judgment},
        _attr{attr},
        _oper{oper},
        _value{value},
        _workflow{std::move(workflow)}
    {
    }

public:
    virtual auto result(Rating* rating) -> std::tuple<RuleResult, std::string> const override;
    virtual void print() const override;

private:
    char _attr;
    RuleOpertion _oper;
    int _value;
    std::string _workflow;
};

class JumpRule : public Rule
{
public:
    JumpRule(std::string workflow) : 
        Rule{RuleType::Jump},
        _workflow{std::move(workflow)}
    {
    }

public:
    virtual auto result(Rating* rating) -> std::tuple<RuleResult, std::string> const override;
    virtual void print() const override;

private:
    std::string _workflow;
};

std::unique_ptr<Rule> makeRule(std::string content);

